home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cool / cool.lha / ice / pisces / pimake / pimake.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-04  |  15.3 KB  |  659 lines

  1. /**
  2.  ** Copyright 1985 - 1987 by the Massachusetts Institute of Technology
  3.  **
  4.  ** Permission to use, copy, modify,  and  distribute this software and
  5.  ** its   documentation  for  any purpose and   without   fee is hereby
  6.  ** granted,  provided that  the above copyright  notice  appear in all
  7.  ** copies and that both   that copyright  notice  and  this permission
  8.  ** notice appear   in supporting documentation,  and that  the name of
  9.  ** M.I.T.   not   be used in   advertising or publicity  pertaining to
  10.  ** distribution  of   the software   without specific,   written prior
  11.  ** permission.  M.I.T.  makes no representations about the suitability
  12.  ** of this software for any purpose.   It is provided  "as is" without
  13.  ** express or implied warranty.
  14.  **
  15.  ** Original Author:
  16.  **    Todd Brunhoff, Tektronix, inc.
  17.  **    While a guest engineer at Project Athena, MIT
  18.  **
  19.  ** Modified by:
  20.  **    Martin Neath, Texas Instruments Incorporated.
  21.  **
  22.  ** Introduction:
  23.  ** =============
  24.  ** Imake uses  the C preprocessor on  a macro-makefile (the Imakefile)
  25.  ** to   generate  a Makefile for   a particular system.   Imake uses a
  26.  ** predefined template  file  for default  values, command  names  and
  27.  ** procedures,  and macros for  a  specific  system.   An Imakefile is
  28.  ** system-independent;  support  for  a new  operating  system or tool
  29.  ** requires only the addition of a template file for that system.  The
  30.  ** Imakefile that specifies the dependencies and relationships between
  31.  ** files in the software system to built does not change.
  32.  **
  33.  ** Options:
  34.  **        -D    define a symbol for the preprocessor
  35.  **        -I    specify include directory for the preprocessor
  36.  **
  37.  ** Usage: imake -D<machine> -DTOPDIR=<dirname> -DREV=<num> -I<config>
  38.  **
  39.  ** Imake is invoked with four arguments: a symbol defining the machine
  40.  ** on which it is being run, a symbol TOPDIR assigned  the name of the
  41.  ** top directory of the source tree, a symbol REV assigned the current
  42.  ** major RCS revision number, and an include search  directory path to
  43.  ** be search for the template and configuration files.
  44.  **
  45.  ** Changes From X11R4 Distribution:
  46.  ** ===============================
  47.  **
  48.  ** This version of Imake is quite different to the original version on
  49.  ** the X11R4 source tape. As originaly  implemented, Imake only ran on
  50.  ** UNIX-like operating systems,  for example assuming that the program
  51.  ** /lib/cpp  was the location of  the C preprocessor. This version has
  52.  ** been significantly modified to run on non-UNIX operating systems to
  53.  ** enhance is usage. Thus, the preprocessor has been  internalized and
  54.  ** is now a  subroutine call.  File names are case  insensitive and do
  55.  ** not violate  the "eight dot  three" name rule for OS/2  and MS-DOS.
  56.  ** Finally, the strings "@@", "@+", "@-", "@#", and "@!" are  used  to
  57.  ** denote the end of line, integer increment, integer decrement,  make
  58.  ** comment line, and escaped-double-quote. These are  processed  after
  59.  ** the preprocessor is run  with the  appropriate  characters inserted
  60.  ** into the generated Makefile.
  61.  **
  62.  ** Theory of Operation:
  63.  **
  64.  ** 1) Start up Imake and process the command  line directives checking
  65.  **    for four arguments specifying machine/system  name, the  tope of
  66.  **    the source directory, a revision number, and a directory path.
  67.  **
  68.  ** 2) Call the preprocessor and provide it with three lines of input:
  69.  **
  70.  **        #define IMAKE_TEMPLATE         "<Imakefile>"
  71.  **        #define INCLUDE_IMAKEFILE      < <imakefile> >
  72.  **        #include IMAKE_TEMPLATE
  73.  **
  74.  **    Note that the  define for INCLUDE_IMAKEFILE  is intended for use
  75.  **    in the template file. The design of the template makefile should
  76.  **    therefore be:
  77.  **
  78.  **        <set global macros like CFLAGS, etc.>
  79.  **        <include machine dependent additions>
  80.  **        #include INCLUDE_IMAKEFILE
  81.  **        <add any global targets like 'clean' and long dependencies>
  82.  **
  83.  ** 3) Gather the output from preprocessor  and  clean it up, expanding
  84.  **    @@ to  newlines, @# to make comment  lines, @+ and  @- to either
  85.  **    increment or  decrement,  respectively,  an  integer number, and
  86.  **    stripping trailing  white space, cpp   control lines,  and extra
  87.  **    blank lines.  This cleaned output is copied to the Makefile.
  88.  **/
  89.  
  90. #include    <stdio.h>
  91. #include    <ctype.h>
  92.  
  93. #ifdef os2
  94. #include    <sys/types.h>
  95. #include    <fcntl.h>
  96. #include    <signal.h>
  97. #include    <sys/stat.h>
  98. #else   /* !os2 */
  99. #ifdef VMS
  100. #include    <types.h>
  101. #include    <file.h>
  102. #include    <signal.h>
  103. #include    <stat.h>
  104. #else    /* ! VMS */
  105. #include    <sys/types.h>
  106. #ifdef SYSV
  107. #ifndef macII            /* mac will get the stuff out of file.h */
  108. #include    <fcntl.h>
  109. #endif
  110. #else    /* !SYSV */
  111. #include    <sys/wait.h>
  112. #endif    /* !SYSV */
  113. #include    <sys/file.h>
  114. #include    <signal.h>
  115. #include    <sys/stat.h>
  116. #endif    /* VMS */
  117. #endif    /* os2 */
  118.  
  119. #include "pimake.h"
  120.  
  121.  
  122. #define    TRUE        1
  123. #define    FALSE        0
  124.  
  125. int    InRule = FALSE;
  126.  
  127. typedef    unsigned char    boolean;
  128.  
  129. #ifdef VMS
  130. #define CPP_PROGRAM "mcr [-.cpp]cpp"
  131. #endif
  132. char *cpp = CPP_PROGRAM;
  133.  
  134. char    *tmpImakefile = NULL;
  135. char    *tmp_file_name = "temp.tmp";
  136. char    *tmp_mkfile_name = "makefile.tmp";
  137.  
  138. int    cpp_argindex;
  139. char    *Imakefile = "Imakefile";
  140. char    *Makefile = "Makefile";
  141. char    *Template = "imake.imk";
  142. char    *program;
  143. char    *FindImakefile();
  144. char    *ReadLine();
  145. char    *CleanCppInput();
  146. char    *strdup();
  147.  
  148. void LogFatal();
  149.  
  150. extern int    errno;
  151. extern char    *Emalloc();
  152. extern char    *realloc();
  153. extern char    *mktemp();
  154.  
  155. #ifdef VMS
  156. /* dzg - added this routine, which is not defined in VMS
  157.  */
  158. void unlink (name)
  159.      char *name;
  160. {
  161.   char command[200];
  162.   /* Use the DELETE command (executed through SYSTEM), since VMS does not
  163.      support UNLINK */
  164.   sprintf (command, "delete %s;", name);
  165.   system (command);
  166. }
  167. #endif
  168.  
  169.  
  170.  
  171. main(argc, argv)
  172.     int    argc;
  173.     char    **argv;
  174. {
  175.      init();
  176.     if( argc != 5) {
  177.          fprintf(stderr, "Usage: pimake -D<machine> -DTOPDIR=<dirname> -DREV=<num> -I<config>\n");
  178.         exit(-1);
  179.     }
  180.     SetOpts(argc, argv);
  181.  
  182.     Imakefile = FindImakefile(Imakefile);
  183.  
  184.     cppit(Imakefile, Template);
  185.      if (tmpImakefile != NULL)
  186.       unlink(tmpImakefile);
  187.      if (tmp_file_name != NULL)
  188.       unlink(tmp_file_name);
  189.      if (tmp_mkfile_name != NULL)
  190.       unlink(tmp_mkfile_name);
  191.     exit(0);
  192. }
  193.  
  194. #if SIGNALRETURNSINT
  195. int
  196. #else
  197. void
  198. #endif
  199. catch(sig)
  200.     int    sig;
  201. {
  202.     errno = 0;
  203.     LogFatalI("Signal %d.", sig);
  204. }
  205.  
  206.  
  207. /*
  208.  * Initialize some variables.
  209.  */
  210. init()
  211. {
  212.     char    *p;
  213.  
  214.     cpp_argindex = 0;
  215.     while (cpp_argv[ cpp_argindex ] != NULL)
  216.         cpp_argindex++;
  217. #ifndef os2
  218.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  219.         signal(SIGINT, catch);
  220. #endif    
  221. }
  222.  
  223. AddCppArg(arg)
  224.     char    *arg;
  225. {
  226.     errno = 0;
  227.     if (cpp_argindex >= ARGUMENTS-1)
  228.         LogFatal("Out of internal storage.", "");
  229.     cpp_argv[ cpp_argindex++ ] = arg;
  230.     cpp_argv[ cpp_argindex ] = NULL;
  231. }
  232.  
  233. SetOpts(argc, argv)
  234.     int    argc;
  235.     char    **argv;
  236. {
  237.         char* TOPDIR[100];
  238.     errno = 0;
  239.     program = argv[0];
  240.     AddCppArg("-I.");
  241.     for(argc--, argv++; argc; argc--, argv++) {
  242.         if (argv[0][0] == '-') {
  243.         if (argv[0][1] == 'D') {
  244.             AddCppArg(argv[0]);
  245.         /**    if( !strcmp(&argv[0][2], "TOPDIR=" )) {
  246.          **      strcpy( TOPDIR, "-I" );
  247.          **      strcat( TOPDIR, &argv[0][2] );
  248.          **      AddCppArg( TOPDIR );
  249.          **   }
  250.          **/
  251.         } else if (argv[0][1] == 'I') {
  252.             AddCppArg(argv[0]);
  253.         }
  254.         }
  255.         else if (argv[0][0] == '/') {
  256.         if (argv[0][1] == 'D') {
  257.             AddCppArg(argv[0]);
  258.         } else if (argv[0][1] == 'I') {
  259.             AddCppArg(argv[0]);
  260.         }
  261.         }
  262.     }
  263. }
  264.  
  265. char *FindImakefile(Imakefile)
  266.     char    *Imakefile;
  267. {
  268.     int    fd;
  269.  
  270.     if ((fd = open(Imakefile, O_RDONLY)) < 0)
  271.         LogFatal("Cannot open %s.", Imakefile);
  272.     close (fd);
  273.     return(Imakefile);
  274. }
  275.  
  276. LogFatalI(s, i)
  277.     char *s;
  278.     int i;
  279. {
  280.     /*NOSTRICT*/
  281.     LogFatal(s, (char *)i);
  282. }
  283.  
  284. void
  285. LogFatal(x0,x1)
  286.     char *x0, *x1;
  287. {
  288. #ifndef VMS
  289.     extern char    *sys_errlist[];
  290. #endif
  291.     static boolean    entered = FALSE;
  292.  
  293.     if (entered)
  294.         return;
  295.     entered = TRUE;
  296.  
  297.     fprintf(stderr, "%s: ", program);
  298. #ifndef VMS
  299.     if (errno)
  300.         fprintf(stderr, "%s: ", sys_errlist[ errno ]);
  301. #endif
  302.     fprintf(stderr, x0,x1);
  303.     fprintf(stderr, "  Stop.\n");
  304.     unlink(tmpImakefile);
  305.     exit(1);
  306. }
  307.  
  308. cppit(Imakefile, template)
  309.      char    *Imakefile;
  310.      char    *template;
  311. {
  312.   char    *cleanedImakefile;
  313.   char  command[200];
  314.   int   i;
  315.   FILE    *outfd;
  316.  
  317.   /* Exec the C preprocessor */
  318.   cleanedImakefile = CleanCppInput(Imakefile, template);
  319.  
  320.   /* Execute the C preprocessor */
  321.   strcpy (command, cpp);
  322.   for (i = 2; i < cpp_argindex; ++i) {
  323. #ifdef VMS
  324.     strcat (command, " \"");
  325. #else
  326.     strcat (command, " ");
  327. #endif
  328.     strcat (command, cpp_argv[i]);
  329. #ifdef VMS
  330.     strcat (command, " \"");
  331. #else
  332.     strcat (command, " ");
  333. #endif
  334.   }
  335.   strcat (command, " ");
  336.   strcat (command, tmp_file_name);
  337.   strcat (command, " ");
  338.   strcat (command, tmp_mkfile_name);
  339.   system (command);
  340.  
  341.   if ((outfd = fopen(Makefile, "w+")) == NULL)
  342.     LogFatal("Cannot create makefile %s.", Makefile);
  343.   CleanCppOutput (outfd, Makefile);
  344. }
  345.  
  346.  
  347. char *CleanCppInput(Imakefile, template)
  348.     char    *Imakefile, *template;
  349. {
  350.   FILE    *outFile = NULL;
  351.   FILE    *infd;
  352.   int    length;
  353.   int    i;
  354.   char    *buf,            /* buffer for file content */
  355.   *start,            /* starting point of actual file data */
  356.   *pbuf,            /* walking pointer to buf */
  357.   *punwritten,            /* pointer to unwritten portion of buf */
  358.   *cleanedImakefile = Imakefile,/* return value */
  359.   *ptoken,            /* pointer to # token */
  360.   *pend,            /* pointer to end of # token */
  361.   savec;            /* temporary character holder */
  362.   struct stat    st;
  363.   FILE *tmpfile;
  364.  
  365.   if ((infd = fopen(Imakefile, "r")) == NULL)
  366.     LogFatal("Cannot open %s for input.", Imakefile);
  367.   if ((tmpfile = fopen (tmp_file_name, "w")) == NULL)
  368.     LogFatal("Cannot open %s for output.", tmp_file_name);
  369.  
  370.   stat (Imakefile, &st);
  371.   buf = Emalloc(st.st_size+1);
  372.   /* Add the first three lines */
  373.   fprintf (tmpfile, "#define IMAKE_TEMPLATE\t\"%s\"\n", template);
  374.   fprintf (tmpfile, "#define INCLUDE_IMAKEFILE\t\"%s\"\n", Imakefile);
  375.   fprintf (tmpfile, "#include \"%s\"\n", template);
  376.   start = buf;
  377.   for (i = 0; i < st.st_size; ++i)
  378.     *start++ = fgetc (infd);
  379.   fclose (infd);
  380.   buf[ st.st_size ] = '\0';
  381.  
  382.   punwritten = pbuf = buf;
  383.   while (*pbuf) {
  384.     /* pad make comments for cpp */
  385.     if (*pbuf == '#' && (pbuf == buf || pbuf[-1] == '\n')) {
  386.  
  387.       ptoken = pbuf+1;
  388.       while (*ptoken == ' ' || *ptoken == '\t')
  389.     ptoken++;
  390.       pend = ptoken;
  391.       while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
  392.     pend++;
  393.       savec = *pend;
  394.       *pend = '\0';
  395.       if (strcmp(ptoken, "include")
  396.       && strcmp(ptoken, "define")
  397.       && strcmp(ptoken, "undef")
  398.       && strcmp(ptoken, "ifdef")
  399.       && strcmp(ptoken, "ifndef")
  400.       && strcmp(ptoken, "else")
  401.       && strcmp(ptoken, "endif")
  402.       && strcmp(ptoken, "if")) {
  403.     if (outFile == NULL) {
  404.       tmpImakefile = mktemp(strdup(tmpImakefile));
  405.       cleanedImakefile = tmpImakefile;
  406.       outFile = fopen(tmpImakefile, "w");
  407.       if (outFile == NULL)
  408.         LogFatal("Cannot open %s for write.\n",
  409.              tmpImakefile);
  410.     }
  411.     fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
  412.     fputs("            /**/", outFile);
  413.     punwritten = pbuf;
  414.       }
  415.       *pend = savec;
  416.     }
  417.     pbuf++;
  418.   }
  419.   if (outFile) {
  420.     fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
  421.     fclose(outFile);        /* also closes the pipe */
  422.   }
  423.  
  424.   /* Output the entire file */
  425. /*  while (*buf)
  426.     putc (*buf++, tmpfile);*/
  427.   fclose (tmpfile);
  428.   return(cleanedImakefile);
  429. }
  430.  
  431. CleanCppOutput(tmpfd, tmpfname)
  432.     FILE    *tmpfd;
  433.     char    *tmpfname;
  434. {
  435.   char    *input;
  436.   int    blankline = 0;
  437.   FILE    *infile = fopen ("makefile.tmp", "r");
  438.  
  439.   while(input = ReadLine (infile, tmpfname)) {
  440. #ifdef os2
  441. if (*input == '\377')
  442.   break;
  443. #endif
  444.     if (isempty(input)) {
  445.       if (blankline++)
  446.     continue;
  447.       KludgeResetRule();
  448.     } else {
  449.       blankline = 0;
  450.       KludgeOutputLine(&input);
  451.       fprintf (tmpfd, "%s",input);
  452.     }
  453.     fprintf (tmpfd, "\n");
  454.   }
  455.   fclose (tmpfd);
  456.   fclose (infile);
  457. }
  458.  
  459. /*
  460.  * Determine if a line has nothing in it.  As a side effect, we trim white
  461.  * space from the end of the line.  Cpp magic cookies are also thrown away.
  462.  */
  463. isempty(line)
  464.     char    *line;
  465. {
  466.     char    *pend;
  467.  
  468.     /*
  469.      * Check for lines of the form
  470.      *    # n "...
  471.      * or
  472.      *    # line n "...
  473.      */
  474.     if (*line == '#') {
  475.         pend = line+1;
  476.         if (*pend == ' ')
  477.             pend++;
  478.         if (strncmp(pend, "line ", 5) == 0)
  479.             pend += 5;
  480.         if (isdigit(*pend)) {
  481.             while (isdigit(*pend))
  482.                 pend++;
  483.             if (*pend++ == ' ' && *pend == '"')
  484.                 return(TRUE);
  485.         }
  486.     }
  487.  
  488.     /*
  489.      * Find the end of the line and then walk back.
  490.      */
  491.     for (pend=line; *pend; pend++) ;
  492.  
  493.     pend--;
  494.     while (pend >= line && (*pend == ' ' || *pend == '\t'))
  495.         pend--;
  496.     *++pend = '\0';
  497.     return (*line == '\0');
  498. }
  499.  
  500. /*ARGSUSED*/
  501. char *ReadLine (tmpfd, tmpfname)
  502.     FILE    *tmpfd;
  503.     char    *tmpfname;
  504. {
  505.   static boolean    initialized = FALSE;
  506.   static char    *buf, *pline, *end;
  507.   char    *p1, *p2;
  508.   char    numbuf[10];
  509.   int     i,num;
  510.  
  511.   if (! initialized) {
  512.     struct stat    st;
  513.     int i;
  514.     /*
  515.      * Slurp it all up.
  516.      */
  517.     fseek(tmpfd, 0, 0);
  518.     fstat(fileno(tmpfd), &st);
  519.     pline = buf = Emalloc(st.st_size+1);
  520.     for (i = 0; i < st.st_size; ++i)
  521.       buf[i] = getc (tmpfd);
  522.     end = buf + st.st_size;
  523.     *end = '\0';
  524.     initialized = TRUE;
  525.   }
  526.  
  527.   for (p1 = pline; p1 < end; p1++) {
  528.     if (*p1 == '@' && *(p1+1) == '+') { /* increment number */
  529.       i = 0;
  530.       p2 = p1+2;
  531.       while (isdigit(*p2))
  532.     numbuf[i++] = *p2++;
  533.       numbuf[i] = '\0';
  534.       num = strlen(numbuf);
  535.       sprintf(numbuf,"%d",atoi(numbuf)+1);
  536.       p2 = numbuf;
  537.       while(*p2)
  538.     *p1++ = *p2++;
  539.       *p1++ = ' ';        /* skip over + character */
  540.       if(strlen(numbuf) == num)
  541.     *p1++ = ' ';
  542.       continue;
  543.     }
  544.     else if (*p1 == '@' && *(p1+1) == '-') { /* decrement number */
  545.       i = 0;
  546.       p2 = p1+2;
  547.       while (isdigit(*p2))
  548.     numbuf[i++] = *p2++;
  549.       numbuf[i] = '\0';
  550.       num = strlen(numbuf);
  551.       sprintf(numbuf,"%d",atoi(numbuf)-1);
  552.       p2 = numbuf;
  553.       while(*p2)
  554.     *p1++ = *p2++;
  555.       *p1++ = ' ';        /* skip over - character */
  556.       *p1++ = ' ';
  557.       if(strlen(numbuf) != num)
  558.     *p1++ = ' ';
  559.       continue;
  560.     }
  561.     else if (*p1 == '@' && *(p1+1) == '#') { /* make comment */
  562.       if (*(p1+2) == '#')
  563.     *p1++ = '#';
  564.       else {
  565.     *p1++ = '#';
  566.     *p1++ = ' ';
  567.       }
  568.       continue;
  569.     }
  570.     else if (*p1 == '@' && *(p1+1) == '!') { /* escaped-quote */
  571.       *p1++ = '\\';
  572.       *p1++ = '"';
  573.       continue;
  574.     }
  575.     else if (*p1 == '@' && *(p1+1) == '/') { /* escaped-backslash */
  576.       *p1++ = '\\';
  577.       *p1++ = ' ';
  578.       continue;
  579.     }
  580.     else if (*p1 == '@' && *(p1+1) == '@') { /* soft EOL */
  581.       *p1++ = '\0';
  582.       p1++;            /* skip over second @ */
  583.       break;
  584.     }
  585.     else if (*p1 == '\n') {    /* real EOL */
  586.       *p1++ = '\0';
  587.       break;
  588.     }
  589.   }
  590.  
  591.   /*
  592.    * return NULL at the end of the file.
  593.    */
  594.   p2 = (pline == p1 ? NULL : pline);
  595.   pline = p1;
  596.   return(p2);
  597. }
  598.  
  599. writetmpfile(fd, buf, cnt)
  600.     FILE    *fd;
  601.     int    cnt;
  602.     char    *buf;
  603. {
  604.     errno = 0;
  605.     if (fwrite(buf, cnt, 1, fd) != 1)
  606.         LogFatal("Cannot write to %s.", Makefile);
  607. }
  608.  
  609. char *Emalloc(size)
  610.     int    size;
  611. {
  612.     char    *p, *malloc();
  613.  
  614.     if ((p = malloc(size)) == NULL)
  615.         LogFatalI("Cannot allocate %d bytes\n", size);
  616.     return(p);
  617. }
  618.  
  619. KludgeOutputLine(pline)
  620.     char    **pline;
  621. {
  622.     char    *p = *pline;
  623.  
  624.     switch (*p) {
  625.         case '#':    /*Comment - ignore*/
  626.         break;
  627.         case '\t':    /*Already tabbed - ignore it*/
  628.             break;
  629.         case ' ':    /*May need a tab*/
  630.         default:
  631.         for (; *p; p++) if (p[0] == ':' && 
  632.                     p > *pline && p[-1] != '\\') {
  633.             if (**pline == ' ')
  634.             (*pline)++;
  635.             InRule = TRUE;
  636.             break;
  637.         }
  638.         if (InRule && **pline == ' ')
  639.             **pline = '\t';
  640.         break;
  641.     }
  642. }
  643.  
  644. KludgeResetRule()
  645. {
  646.     InRule = FALSE;
  647. }
  648.  
  649. char *strdup(cp)
  650.     register char *cp;
  651. {
  652.     register char *new = Emalloc(strlen(cp) + 1);
  653.  
  654.     strcpy(new, cp);
  655.     return new;
  656. }
  657.  
  658.  
  659.